#ifndef BTL_UTILITY_OPENCVSUPPORT
#define BTL_UTILITY_OPENCVSUPPORT

#include <btl/Image/Image.hpp>
#include <btl/Image/PixelTypes.hpp>
#include <opencv2/core/core.hpp>

namespace btl {
namespace utility {

template <class PixelT>
struct CvPixelTraits {};

template <>
struct CvPixelTraits<btl::PixelRGB>
{
    static const int CvPixelType = CV_8UC3;
};

template <>
struct CvPixelTraits<btl::PixelGrey>
{
    static const int CvPixelType = CV_8UC1;
};

template <>
struct CvPixelTraits<btl::PixelFloat>
{
    static const int CvPixelType = CV_32FC1;
};

/// OpenCV has no way of representing the const-ness of an image
/// (to my knowledge); so this just const_cast<>s away the constness
/// of the pixel data; this is unsafe (hence the name), but provided
/// because without it someone would just re-implement it, or revert
/// to const-incorrect code through the rest of the BTL
template <class PixelT>
cv::Mat cvUnsafeUnconstImage ( const btl::ImageRegion<const PixelT>& im );

template <class PixelT>
cv::Mat cvImage ( btl::ImageRegion<PixelT>& im );

template <class PixelT>
cv::Mat cvImage ( btl::Image<PixelT>& im );

template <class PixelT, int W, int H>
cv::Mat cvImage ( btl::SmallImage<PixelT, W, H>& im );

}
}

namespace btl
{
using utility::cvImage;
using utility::cvUnsafeUnconstImage;
}

// ====================================================================
// === Implementation

namespace btl {
namespace utility {

template <class T>
inline cv::Mat cvUnsafeUnconstImage ( const btl::ImageRegion<const T>& im )
{
    return cv::Mat (
               im.height(), im.width(),
               CvPixelTraits<T>::CvPixelType,
               const_cast<T*> ( im.data() ), im.stride()
           );
}

template <class T>
inline cv::Mat cvImage ( btl::ImageRegion<T>& im )
{
    return cv::Mat (
               im.height(), im.width(),
               CvPixelTraits<T>::CvPixelType,
               im.data(), im.stride()
           );
}

template <class T>
inline cv::Mat cvImage ( btl::Image<T>& im )
{
    return cvImage ( static_cast<btl::ImageRegion<T>&> ( im ) );
}

template <class T, int W, int H>
inline cv::Mat cvImage ( btl::SmallImage<T, W, H>& im )
{
    btl::ImageRegion<T> imrg = im;
    return cvImage ( imrg );
}

}
}

#endif
